package org.jeecg.modules.system.service.impl;

import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DictCode;
import org.jeecg.common.constant.enums.SysLogConfig;
import org.jeecg.common.constant.enums.SysLogOperateType;
import org.jeecg.common.constant.enums.SysLogType;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.system.entity.SysDict;
import org.jeecg.modules.system.entity.SysDictItem;
import org.jeecg.modules.system.entity.SysLog;
import org.jeecg.modules.system.entity.SysLogBackup;
import org.jeecg.modules.system.mapper.SysDictItemMapper;
import org.jeecg.modules.system.mapper.SysDictMapper;
import org.jeecg.modules.system.mapper.SysLogBackupMapper;
import org.jeecg.modules.system.mapper.SysLogMapper;
import org.jeecg.modules.system.mapper.SysRoleMapper;
import org.jeecg.modules.system.service.ISysLogService;
import org.jeecg.modules.system.vo.SysLogColumnarStatisticsVO;
import org.jeecg.modules.system.vo.SysLogConfigReq;
import org.jeecg.modules.system.vo.SysLogPageReq;
import org.jeecg.modules.system.vo.SysLogStatisticsReq;
import org.jeecg.modules.system.vo.SysLogStatisticsVO;
import org.jeecg.modules.system.vo.SysLogVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * <p>
 * 系统日志表 服务实现类
 * </p>
 *
 * @Author zhangweijian
 * @since 2018-12-26
 */
@Service
public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements ISysLogService {

	@Resource
	private SysLogMapper sysLogMapper;

	@Resource
	private SysLogBackupMapper sysLogBackupMapper;

	@Resource
	private SysRoleMapper sysRoleMapper;

	@Autowired
	private ISysBaseAPI sysBaseAPI;

	@Autowired
	private SysDictMapper sysDictMapper;

	@Autowired
	private SysDictItemMapper sysDictItemMapper;

	/**
	 * @功能：清空所有日志记录
	 */
	@Override
	public void removeAll() {
		sysLogMapper.removeAll();
	}

	@Override
	public Long findTotalVisitCount() {
		return sysLogMapper.findTotalVisitCount();
	}

	// update-begin--Author:zhangweijian Date:20190428 for：传入开始时间，结束时间参数
	@Override
	public Long findTodayVisitCount(Date dayStart, Date dayEnd) {
		return sysLogMapper.findTodayVisitCount(dayStart, dayEnd);
	}

	@Override
	public Long findTodayIp(Date dayStart, Date dayEnd) {
		return sysLogMapper.findTodayIp(dayStart, dayEnd);
	}
	// update-end--Author:zhangweijian Date:20190428 for：传入开始时间，结束时间参数

	@Override
	public List<Map<String, Object>> findVisitCount(Date dayStart, Date dayEnd) {
		try {
			String dbType = sysBaseAPI.getDatabaseType();
			return sysLogMapper.findVisitCount(dayStart, dayEnd, dbType);
		} catch (SQLException e) {
		}
		return null;
	}

	@Override
	public IPage<SysLogVO> queryPage(Page<SysLog> page, SysLogPageReq sysLogPageReq) {
		compareDate(sysLogPageReq.getStartTime(), sysLogPageReq.getEndTime());

		boolean isExclusion = false;
		if (sysLogPageReq.getEventType() != null) {
			List<Integer> operateTypes = sysLogPageReq.getOperateType();
			List<Integer> s = new ArrayList<>();
			flag: for (SysLogOperateType operateType : SysLogOperateType.values()) {
				if (operateType.getIsSystem() != null && sysLogPageReq.getEventType() == (operateType.getIsSystem() ? 1 : 0)) {
					if (operateTypes != null) {
						for (Integer type : operateTypes) {
							if (type == operateType.getType()) {
								s.add(type);
							}
						}
					} else {
						s.add(operateType.getType());
					}
				} else {
					// 如果互斥，将res置空
					if (operateTypes != null) {
						for (Integer type : operateTypes) {
							if (type == operateType.getType()) {
								isExclusion = true;
								break flag;
							}
						}
					}
				}
			}
			sysLogPageReq.setOperateType(s);

		}
		IPage<SysLogVO> res = sysLogMapper.queryPage(page, sysLogPageReq, null);

		if (isExclusion) {
			res.setRecords(new ArrayList<>());
		}

		if (sysLogPageReq != null && sysLogPageReq.getLogType() != null && sysLogPageReq.getLogType().size() == 1 && sysLogPageReq.getLogType().get(0).equals(SysLogType.ALARM.getType())) {
			Map<Integer, Integer> countMap = new HashMap<>();
			List<SysLog> logs = sysLogMapper.selectList(new QueryWrapper<SysLog>().eq("log_type", SysLogType.ALARM.getType()));
			if (logs != null) {
				for (SysLog log : logs) {
					Integer count = countMap.get(log.getOperateType());
					if (count == null) {
						count = 1;
					} else {
						count++;
					}
					countMap.put(log.getOperateType(), count);
				}

				if (res.getRecords() != null) {
					for (SysLogVO vo : res.getRecords()) {
						vo.setCount(countMap.get(vo.getOperateType()));
					}
				}
			}
		}

		return res;
	}

	@Override
	public IPage<SysLogStatisticsVO> logStatistics(Page<SysLogStatisticsVO> page, SysLogStatisticsReq sysLogStatisticsRwq) {
		removeLogDeleteForSgccaqsj(sysLogStatisticsRwq);
		
		IPage<SysLogStatisticsVO> res = null;

		String startTime = null;
		String endTime = null;
		
		if (StringUtils.isEmpty(sysLogStatisticsRwq.getStartTime()) && StringUtils.isEmpty(sysLogStatisticsRwq.getEndTime())) {
			res = sysLogMapper.logStatistics(page, sysLogStatisticsRwq, false);
		} else {
			// 转换下时间格式
			if (sysLogStatisticsRwq.getStartTime() != null) {
				startTime = sysLogStatisticsRwq.getStartTime();
				sysLogStatisticsRwq.setStartTime(sysLogStatisticsRwq.getStartTime() + " 00:00");
			}
			if (sysLogStatisticsRwq.getEndTime() != null) {
				endTime = sysLogStatisticsRwq.getEndTime();
				sysLogStatisticsRwq.setEndTime(sysLogStatisticsRwq.getEndTime() + " 23:59");
			}
			res = sysLogMapper.logStatistics(page, sysLogStatisticsRwq, false);
		}

		if (res != null && res.getRecords() != null) {
			for (SysLogStatisticsVO vo : res.getRecords()) {
				if (StringUtils.isEmpty(sysLogStatisticsRwq.getUsername())) {
					vo.setUsername(null);
				}

				if (StringUtils.isEmpty(sysLogStatisticsRwq.getStartTime()) && StringUtils.isEmpty(sysLogStatisticsRwq.getEndTime())) {
					vo.setDate(null);
				} else {
					vo.setDate(startTime + "至" + endTime);
				}
			}
		}

		return res;
	}

	private void removeLogDeleteForSgccaqsj(SysLogStatisticsReq sysLogStatisticsRwq) {
		List<String> userIdAqsj = new ArrayList<>();
		userIdAqsj.add("sgccaqsj");
		// 获取登录用户信息
		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
		if (sysUser !=null) {
			for (String userId :userIdAqsj) {
				if (sysUser.getUsername().startsWith(userId)) {
					if (sysLogStatisticsRwq.getExcludeOperateType() == null) {
						sysLogStatisticsRwq.setExcludeOperateType(new ArrayList<Integer>());
					}
					
					sysLogStatisticsRwq.getExcludeOperateType().add(CommonConstant.OPERATE_TYPE_LOG_DELETE); // 日志删除
				}
			}
		}
	}

	@Override
	public List<SysLogColumnarStatisticsVO> columnarStatistics(SysLogStatisticsReq sysLogStatisticsRwq) {
		removeLogDeleteForSgccaqsj(sysLogStatisticsRwq);
		
		
		List<SysLogColumnarStatisticsVO> result = new ArrayList<>();
		Page<SysLogStatisticsVO> page = new Page<SysLogStatisticsVO>(1, 99999);
		if (sysLogStatisticsRwq.getStartTime() != null) {
			sysLogStatisticsRwq.setStartTime(sysLogStatisticsRwq.getStartTime() + " 00:00");
		}
		if (sysLogStatisticsRwq.getEndTime() != null) {
			sysLogStatisticsRwq.setEndTime(sysLogStatisticsRwq.getEndTime() + " 23:59");
		}
		IPage<SysLogStatisticsVO> res = sysLogMapper.logStatistics(page, sysLogStatisticsRwq, false);
		List<SysLogStatisticsVO> list = res.getRecords();
		if (list != null) {
			for (SysLogStatisticsVO v : list) {
				SysLogColumnarStatisticsVO vo = new SysLogColumnarStatisticsVO();
				vo.setFail(v.getFail());
				vo.setOperateType(v.getOperateType());
				vo.setOperateTypeName(v.getOperateTypeName());
				vo.setSuccess(v.getSuccess());
				vo.setTotal(v.getTotal());
				result.add(vo);
			}
		}

		return result;
	}

	@Override
	public Map<String, Integer> config(SysLogConfigReq req) {

		SysDict dict = sysDictMapper.selectOne(new QueryWrapper<SysDict>().eq("dict_code", DictCode.LOG_CONFIG.getCode()));
		if (dict == null) {
			dict = new SysDict();
			dict.setId("1342732234116886529");
			dict.setDictName(DictCode.LOG_CONFIG.getName());
			dict.setDictCode(DictCode.LOG_CONFIG.getCode());
			dict.setDelFlag(CommonConstant.DEL_FLAG_0);
			sysDictMapper.insert(dict);
		}
		// 查询数据库的item,重置req
		Map<String, Object> queryItem = new HashMap<>();
		queryItem.put("dict_id", dict.getId());
		List<SysDictItem> items = sysDictItemMapper.selectByMap(queryItem);
		Map<String, Integer> itemMap = new HashMap<>();
		if (items != null && items.size() > 0) {
			for (SysDictItem item : items) {
				itemMap.put(item.getItemText(), item.getItemValue() == null ? 0 : Integer.valueOf(item.getItemValue()));
			}
		}
		req.setAddSwitch(req.getAddSwitch() == null ? itemMap.get("addSwitch") : req.getAddSwitch());
		req.setAppQuerySwitch(req.getAppQuerySwitch() == null ? itemMap.get("appQuerySwitch") : req.getAppQuerySwitch());
		req.setCapacity(req.getCapacity() == null ? itemMap.get("capacity") : req.getCapacity());
		req.setDeleteSwitch(req.getDeleteSwitch() == null ? itemMap.get("deleteSwitch") : req.getDeleteSwitch());
		req.setDetailSwitch(req.getDetailSwitch() == null ? itemMap.get("detailSwitch") : req.getDetailSwitch());
		req.setListSwitch(req.getListSwitch() == null ? itemMap.get("listSwitch") : req.getListSwitch());
		req.setSqlSwitch(req.getSqlSwitch() == null ? itemMap.get("sqlSwitch") : req.getSqlSwitch());
		req.setUpdateSwitch(req.getUpdateSwitch() == null ? itemMap.get("updateSwitch") : req.getUpdateSwitch());
		Map<String, Object> columnMap = new HashMap<>();
		columnMap.put("dict_id", dict.getId());
		sysDictItemMapper.deleteByMap(columnMap);

		SysDictItem listDict = new SysDictItem();
		listDict.setDictId(dict.getId());
		listDict.setItemText(SysLogConfig.LIST_SWITCH.getName());
		listDict.setItemValue(String.valueOf(req.getListSwitch()));
		sysDictItemMapper.insert(listDict);

		SysDictItem detailDict = new SysDictItem();
		detailDict.setDictId(dict.getId());
		detailDict.setItemText(SysLogConfig.DETAIL_SWITCH.getName());
		detailDict.setItemValue(String.valueOf(req.getDetailSwitch()));
		sysDictItemMapper.insert(detailDict);

		SysDictItem addDict = new SysDictItem();
		addDict.setDictId(dict.getId());
		addDict.setItemText(SysLogConfig.ADD_SWITCH.getName());
		addDict.setItemValue(String.valueOf(req.getAddSwitch()));
		sysDictItemMapper.insert(addDict);

		SysDictItem updateDict = new SysDictItem();
		updateDict.setDictId(dict.getId());
		updateDict.setItemText(SysLogConfig.UPDATE_SWITCH.getName());
		updateDict.setItemValue(String.valueOf(req.getUpdateSwitch()));
		sysDictItemMapper.insert(updateDict);

		SysDictItem deleteDict = new SysDictItem();
		deleteDict.setDictId(dict.getId());
		deleteDict.setItemText(SysLogConfig.DELETE_SWITCH.getName());
		deleteDict.setItemValue(String.valueOf(req.getDeleteSwitch()));
		sysDictItemMapper.insert(deleteDict);

		SysDictItem sqlDict = new SysDictItem();
		sqlDict.setDictId(dict.getId());
		sqlDict.setItemText(SysLogConfig.SQL_SWITCH.getName());
		sqlDict.setItemValue(String.valueOf(req.getSqlSwitch()));
		sysDictItemMapper.insert(sqlDict);

		SysDictItem capacityDict = new SysDictItem();
		capacityDict.setDictId(dict.getId());
		capacityDict.setItemText(SysLogConfig.CAPACITY.getName());
		capacityDict.setItemValue(String.valueOf(req.getCapacity()));
		sysDictItemMapper.insert(capacityDict);

		SysDictItem appQueryDict = new SysDictItem();
		appQueryDict.setDictId(dict.getId());
		appQueryDict.setItemText(SysLogConfig.APPQUERY_SWITCH.getName());
		appQueryDict.setItemValue(String.valueOf(req.getAppQuerySwitch()));
		sysDictItemMapper.insert(appQueryDict);

		// sysBaseAPI.addLog("日志容量修改为" + String.valueOf(req.getCapacity()) + "G", SysLogType.OPERATE, SysLogOperateType.LOG_CONFIG, null, null, "系统管理-日志配置");
		return itemMap;
	}

	/**
	 * 比较时间
	 * 
	 * @param start
	 * @param end
	 */
	private static void compareDate(String start, String end) {
		if (StringUtils.isEmpty(start) || StringUtils.isEmpty(end)) {
			return;
		}
		String pattern = "yyyy/MM/dd HH:mm:ss";
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
		Date startTime = null;
		Date endTime = null;
		try {
			startTime = simpleDateFormat.parse(start);
			endTime = simpleDateFormat.parse(end);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		if (startTime.compareTo(endTime) >= 0) {
			throw new JeecgBootException("开始时间要在结束时间之后");
		}
	}

	@Override
	public void backup(SysLogPageReq sysLogPageReq) {
		Page<SysLog> page = new Page<SysLog>(1, 9999999);
		IPage<SysLogVO> res = sysLogMapper.queryPage(page, sysLogPageReq, null);

		if (res != null && res.getRecords() != null) {
			for (SysLog log : res.getRecords()) {
				SysLogBackup sysLogBackup = sysLogBackupMapper.selectById(log.getId());
				SysLogBackup bak = new SysLogBackup();
				BeanUtils.copyProperties(log, bak);
				if (sysLogBackup == null) {
					sysLogBackupMapper.insert(bak);
				} else {
					sysLogBackupMapper.updateById(bak);
				}
			}
		}

	}

	@Override
	public void resume(SysLogPageReq sysLogPageReq) {
		Calendar c = Calendar.getInstance();
		c.add(Calendar.MONTH, -6);

		String time = DateUtils.date2Str(c.getTime(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

		sysLogPageReq.setEndTime(time);

		Page<SysLog> page = new Page<SysLog>(1, 9999999);
		IPage<SysLogVO> res = sysLogBackupMapper.queryPage(page, sysLogPageReq, null);

		for (SysLogVO resumeLog : res.getRecords()) {
			
			SysLog sysLog = sysLogMapper.selectById(resumeLog.getId());
			SysLog resume = new SysLog();
			BeanUtils.copyProperties(resumeLog, resume);

			if (sysLog == null) {
				sysLogMapper.insert(resume);
			} else {
				sysLogMapper.updateById(resume);
			}
		}

	}

	@Override
	public void deleteLogs(SysLogPageReq sysLogPageReq) {
		Calendar c = Calendar.getInstance();
		c.add(Calendar.MONTH, -6);

		String time = DateUtils.date2Str(c.getTime(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

		sysLogPageReq.setEndTime(time);
		Page<SysLog> page = new Page<SysLog>(1, 9999999);
		IPage<SysLogVO> res = sysLogMapper.queryPage(page, sysLogPageReq, null);

		if (res != null && res.getRecords() != null) {
			for (SysLog log : res.getRecords()) {
				sysLogMapper.deleteById(log);
			}
		}
		
	}
}
